package com.example.lua_redis_demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 用redis incr 生成顺序id 超过最大值复写
 */
@Service
public class RedisIdService {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private LuaService luaService;

    private static final AtomicInteger start = new AtomicInteger(0);
    private static final AtomicInteger end = new AtomicInteger(0);

    /**
     * 停服重启之后,redis 有值，而start end 都是0
     * 所以会跳跃一个跨度 重新增长
     * 如：id=11  重启，这时候会从19开始
     * @param max
     * @param distance
     * @return
     */
    public Integer genId(Integer max,Integer distance) {
        int top = max-1;
        if (end.get() <= start.get() || start.get() == top) {

            try {
                //分布式锁
//                boolean hasLock = luaService.lock("lock_for_gen_id", Thread.currentThread().getName(), 5, TimeUnit.SECONDS);
                Boolean hasLock = stringRedisTemplate.opsForValue().setIfAbsent("lock_for_gen_id", Thread.currentThread().getName(), 5, TimeUnit.SECONDS);
                if (hasLock && (end.get() <= start.get()  || start.get() == top)) {
                    Long gen = stringRedisTemplate.opsForValue().increment("generator_id", distance);
                    if(gen == null){
                        throw new RuntimeException("genId increment  Error ");
                    }
                    int id = gen.intValue();
                    if((id) > max){
                        start.set(0);
                        end.set(0);
                        stringRedisTemplate.opsForValue().set("generator_id", "0");
                        return max;
                    }
                    end.set(id);
                    start.set(id - distance);
                    return start.incrementAndGet();
                }
                return null;
            } finally {
                luaService.releaseLock("lock_for_gen_id", Thread.currentThread().getName());
            }
        }
        return start.incrementAndGet();
    }
}
